class IUP_IMAGE
-- Creates an image to be shown on a label, button, toggle, or as a 
-- cursor.
--
-- Application icons are usually 32x32. Toolbar bitmaps are 24x24 or smaller. 
-- Menu bitmaps and small icons are 16x16 or smaller.
--
-- Images created with the procedure "image" can be reused in different 
-- elements.
--
-- The images should be destroyed when they are no longer necessary, by means 
-- of the "destroy" feature. To destroy an image, it cannot be in use, i.e the 
-- controls where it is used should be destroyed first. Images that were 
-- associated with controls by names are automatically destroyed in "close".
--
-- Please observe the rules for creating cursor images: CURSOR.
--
-- In all drivers, a path to a file name can also be used as the attribute 
-- value. But the available file formats supported are system dependent. The 
-- Windows driver supports BMP, ICO and CUR. The GTK driver supports the 
-- formats supported by the GDK-PixBuf library, such as BMP, GIF, JPEG, PCX, 
-- PNG, TIFF and many others. The Motif driver supports the X-Windows 
-- bitmap.
--
-- For the procedure creation "image", if a color is not set (with 
-- "set_color_at_index"), then it is used a default color for the 16 first 
-- colors. The default color table is the same for Windows, GTK and Motif:
--
-- 0 =   0,  0,  0 (black)
-- 1 = 128,  0,  0 (dark red)
-- 2 =   0,128,  0 (dark green) 
-- 3 = 128,128,  0 (dark yellow)
-- 4 =   0,  0,128 (dark blue)
-- 5 = 128,  0,128 (dark magenta) 
-- 6 =   0,128,128 (dark cian) 
-- 7 = 192,192,192 (gray)
-- 8 = 128,128,128 (dark gray)
-- 9 = 255,  0,  0 (red)     
-- 10 =   0,255,  0 (green)
-- 11 = 255,255,  0 (yellow)
-- 12 =   0,  0,255 (blue)
-- 13 = 255,  0,255 (magenta)
-- 14 =   0,255,255 (cian)  
-- 15 = 255,255,255 (white)
--
-- For images with more than 16 colors, and up to 256 colors, all the color 
-- indices must be defined up to the maximum number of colors. For example, if 
-- the biggest image index is 100, then all the colors from i=16 up to i=100 
-- must be defined even if some indices are not used.

inherit
	IUP_WIDGET
	IUP_WIDGET_INTERNALS
	IUP_WIDGET_BGCOLOR

create {ANY}
	image,
	image_rgb,
	image_rgba,
	load

create {CD_CLIENT_IMAGES}
	with_internal

feature {ANY}

	image (pixels: FAST_ARRAY2[INTEGER])
		-- pixels: Array containing the value of each pixel, 1 value per pixel. 
		-- Origin is at the top-left corner and data is oriented top to bottom, 
		-- and left to right.
		local
			a_image: POINTER
		do
			a_image := int_image(pixels.count2, pixels.count1, convert_array2(pixels))

			if a_image.is_not_null then
				set_widget(a_image)
			end
		end

	image_rgb (pixels: FAST_ARRAY2[TUPLE[INTEGER, INTEGER, INTEGER]])
		-- pixels: Array containing the value of each pixel, 3 values per pixel. 
		-- Origin is at the top-left corner and data is oriented top to bottom, 
		-- and left to right.
		local
			a_image: POINTER
		do
			a_image := int_image_rgb(pixels.count2, pixels.count1,
			                         convert_rgb_array2(pixels))

			if a_image.is_not_null then
				set_widget(a_image)
			end
		end

	image_rgba (pixels: FAST_ARRAY2[TUPLE[INTEGER, INTEGER, INTEGER, INTEGER]])
		-- pixels: Array containing the value of each pixel, 4 values per pixel. 
		-- Origin is at the top-left corner and data is oriented top to bottom, 
		-- and left to right.
		local
			a_image: POINTER
		do
			a_image := int_image_rgba(pixels.count2, pixels.count1,
			                          convert_rgba_array2(pixels))

			if a_image.is_not_null then
				set_widget(a_image)
			end
		end

	load (file_name: STRING)
		-- An image loaded from a file. Supported formats: BMP, JPEG, GIF, TIFF, 
		-- PNG, PNM, PCX, ICO and others.
		local
			a_image: POINTER
		do
			a_image := int_load(file_name.to_external)

			if a_image.is_not_null then
				set_widget(a_image)
			end
		end

	was_created: BOOLEAN
  	   -- Return "True" if no error when create the image. Useful to 
  	   -- be used when an image is created with "load".
		do
			if widget.is_not_null then
				Result := True
			else
				Result := False
			end
		end

	get_error: STRING
		-- Return: NO_ERROR if success, otherwise return the error reported 
  	   -- by the system. Useful to get the error if there is one 
  	   -- when create an image with "load".
		do
			if widget.is_not_null then
				Result := "NO_ERROR"
			else
				Result := iup_open.get_global_attribute("IUPIM_LASTERROR")
			end
		end

	-- Operations

	save (file_name, format: STRING): STRING
		-- Save the image.
		-- file_name: Name of the file to be saved.
		-- format: format descriptor for IM (the library IM used internally). For 
		-- ex: "BMP", "JPEG", "GIF", "TIFF", "PNG", "PNM", "PCX", "ICO", etc.
		-- Return: NO_ERROR if success, otherwise return the error reported 
		-- by the system.
		local
			i: INTEGER
		do
			i := int_save(file_name.to_external, format.to_external)

			if not i.is_equal(0) then
				Result := "NO_ERROR"
			else
				Result := iup_open.get_global_attribute("IUPIM_LASTERROR")
			end	
		end

	-- Attributes

	set_color_at_index (rgb: STRING; index: INTEGER)
		-- The indices can range from 0 to 255. The total number of colors is 
		-- limited to 256 colors. Be careful when setting colors, since they are 
		-- attributes they follow the same storage rules for standard attributes.
		--
		-- The values are integer numbers from 0 to 255, one for each color in 
		-- the RGB triple (For ex: "64 190 255"). If the value of a given index 
		-- is "BGCOLOR", the color used will be the background color of the 
		-- element on which the image will be inserted. The "BGCOLOR" value must 
		-- be defined within an index less than 16.
		--
		-- Used only for images created "image".
		require
			index >= 0
			index <= 255
			is_valid_rgb_string(rgb)
		do
			iup_open.set_attribute(Current, index.to_string, rgb)
		end

	set_auto_scale (value: REAL_32)
		-- Automatically scale the image by a given real factor. If not defined 
		-- the global attribute IMAGEAUTOSCALE will be used. Values are the same 
		-- of the global attribute. 
		do
			iup_open.set_attribute(Current, "AUTOSCALE", value.to_string)
		end

	get_bpp: INTEGER
		-- Returns the number of bits per pixel in the image. Images created 
		-- with "image" returns 8, with "image_rgb" returns 24 and with 
		-- "image_rgba" returns 32.
		local
			str: STRING
		do
			str := iup_open.get_attribute(Current, "BPP")

			if str.is_integer then
				Result := str.to_integer
			end
		end

	-- Skip CLEARCACHE

	get_channels: INTEGER
		-- Returns the number of channels in the image. Images created with 
		-- "image" returns 1, with "image_rgb" returns 3 and with 
		-- "image_rgba" returns 4.
		local
			str: STRING
		do
			str := iup_open.get_attribute(Current, "CHANNELS")

			if str.is_integer then
				Result := str.to_integer
			end
		end

	get_height: INTEGER
		-- Image height in pixels.
		local
			str: STRING
		do
			str := iup_open.get_attribute(Current, "HEIGHT")

			if str.is_integer then
				Result := str.to_integer
			end
		end

	set_hot_spot (x, y: INTEGER)
		-- Hotspot is the position inside a cursor image indicating the 
		-- mouse-click spot. Its value is given by the x and y coordinates inside 
		-- a cursor image. Default: "0:0".
		require
			x >= 0
			y >= 0
		local
			v: STRING
		do
			v := x.to_string
			v.append_string(":")
			v.append_string(y.to_string)

			iup_open.set_attribute(Current, "HOTSPOT", v)
		end

	get_rastersize: TUPLE[INTEGER, INTEGER]
		-- Returns the Current size, in pixels.
		local
			size: STRING
		do
			size := iup_open.get_attribute(Current, "RASTERSIZE")
			Result := components_of_size(size)			
		end

	-- Skip RESHAPE

	resize_to (width, height: INTEGER)
		-- Given a new size changes WIDTH and HEIGHT attributes, and resizes the 
		-- image contents using bilinear interpolation. Works only for RGB and 
		-- RGBA images. 
		require
			width > 0
			height > 0
		local
			v: STRING
		do
			v := width.to_string
			v.append_string("x")
			v.append_string(height.to_string)

			iup_open.set_attribute(Current, "RESIZE", v)
		end

	get_width: INTEGER
		-- Image width in pixels.
		local
			str: STRING
		do
			str := iup_open.get_attribute(Current, "WIDTH")

			if str.is_integer then
				Result := str.to_integer
			end
		end

feature {CD_CLIENT_IMAGES}

	with_internal (a_image: POINTER)
		do
			set_widget(a_image)
		end

	get_wid: POINTER
		-- Returns the internal pixels data pointer.
		do
			Result := int_get_attribute(widget, "WID".to_external)
		end

feature {}

	-- Internals

	int_image (width, height: INTEGER; pixels: NATIVE_ARRAY[CHARACTER]): POINTER
	external "plug_in"
      alias "{
         location: "${sys}/plugins"
         module_name: "iup"
         feature_name: "IupImage"
         }"
      end

	int_image_rgb (width, height: INTEGER; pixels: NATIVE_ARRAY[CHARACTER]): POINTER
	external "plug_in"
      alias "{
         location: "${sys}/plugins"
         module_name: "iup"
         feature_name: "IupImageRGB"
         }"
      end

	int_image_rgba (width, height: INTEGER; pixels: NATIVE_ARRAY[CHARACTER]): POINTER
	external "plug_in"
      alias "{
         location: "${sys}/plugins"
         module_name: "iup"
         feature_name: "IupImageRGBA"
         }"
      end

	int_load(file_name: POINTER): POINTER
		external "plug_in"
      alias "{
         location: "${sys}/plugins"
         module_name: "iup"
         feature_name: "IupLoadImage"
         }"
      end

	int_save(file_name, format: POINTER): INTEGER
		external "plug_in"
      alias "{
         location: "${sys}/plugins"
         module_name: "iup"
         feature_name: "IupSaveImage"
         }"
      end

	int_get_attribute (wgt, name: POINTER): POINTER
      external "plug_in"
      alias "{
         location: "${sys}/plugins"
         module_name: "iup"
         feature_name: "IupGetAttribute"
         }"
      end

	-- Conversion

	convert_array2 (matrix: FAST_ARRAY2[INTEGER]): NATIVE_ARRAY[CHARACTER]
		local
			w, h, v: INTEGER;
			arg: NATIVE_ARRAY[CHARACTER]
			i, x, y: INTEGER
		do
			h := matrix.count1
			w := matrix.count2
			arg := arg.calloc(w*h)
			i := 0
			
			from
				x := 0
         until
				x = w
         loop
				from
					y := 0
				until
					y = h
				loop
					v := matrix.item(x, y)
					arg.put(v.to_character, i)
					i := i + 1
					y := y + 1
				end

				x := x + 1
         end
			
			Result := arg
		end

	convert_rgb_array2 (matrix: FAST_ARRAY2[TUPLE[INTEGER, INTEGER, INTEGER]]): NATIVE_ARRAY[CHARACTER]
		local
			w, h: INTEGER;
			arg: NATIVE_ARRAY[CHARACTER]
			i, x, y: INTEGER
			v: TUPLE[INTEGER, INTEGER, INTEGER]
		do
			h := matrix.count1
			w := matrix.count2
			arg := arg.calloc(3*w*h)
			i := 0
			
			from
				x := 0
         until
				x = w
         loop
				from
					y := 0
				until
					y = h
				loop
					v := matrix.item(x, y)
					arg.put(v.item_1.to_character, i)
					i := i + 1
					arg.put(v.item_2.to_character, i)
					i := i + 1
					arg.put(v.item_3.to_character, i)
					i := i + 1
					
					y := y + 1
				end

				x := x + 1
         end
			
			Result := arg
		end

	convert_rgba_array2 (matrix: FAST_ARRAY2[TUPLE[INTEGER, INTEGER, INTEGER, INTEGER]]): NATIVE_ARRAY[CHARACTER]
		local
			w, h: INTEGER;
			arg: NATIVE_ARRAY[CHARACTER]
			i, x, y: INTEGER
			v: TUPLE[INTEGER, INTEGER, INTEGER, INTEGER]
		do
			h := matrix.count1
			w := matrix.count2
			arg := arg.calloc(4*w*h)
			i := 0
			
			from
				x := 0
         until
				x = w
         loop
				from
					y := 0
				until
					y = h
				loop
					v := matrix.item(x, y)
					arg.put(v.item_1.to_character, i)
					i := i + 1
					arg.put(v.item_2.to_character, i)
					i := i + 1
					arg.put(v.item_3.to_character, i)
					i := i + 1
					arg.put(v.item_4.to_character, i)
					i := i + 1
					
					y := y + 1
				end

				x := x + 1
         end
			
			Result := arg
		end

end

-- The MIT License (MIT)

-- Copyright (c) 2016, 2018 by German A. Arias

-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in 
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
